package org.jeecg.common.util.dynamic.db;

import freemarker.cache.StringTemplateLoader;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.StringWriter;
import java.util.Map;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecgframework.codegenerate.generate.util.SimpleFormat;

/**
 * @author 赵俊夫
 * @version V1.0 @Title:FreemarkerHelper
 * @description:Freemarker引擎协助类
 * @date Jul 5, 2013 2:58:29 PM
 */
@Slf4j
public class FreemarkerParseFactory {

  private static final String ENCODE = "utf-8";
  /** 参数格式化工具类 */
  private static final String MINI_DAO_FORMAT = "DaoFormat";

  /** 文件缓存 */
  private static final Configuration _tplConfig = new Configuration();
  /** SQL 缓存 */
  private static final Configuration _sqlConfig = new Configuration();

  private static StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();

  // 使用内嵌的(?ms)打开单行和多行模式
  private static final Pattern p = Pattern.compile("(?ms)/\\*.*?\\*/|^\\s*//.*?$");

  static {
    _tplConfig.setClassForTemplateLoading(new FreemarkerParseFactory().getClass(), "/");
    _tplConfig.setNumberFormat("0.#####################");
    _sqlConfig.setTemplateLoader(stringTemplateLoader);
    _sqlConfig.setNumberFormat("0.#####################");
    // classic_compatible设置，解决报空指针错误
    _sqlConfig.setClassicCompatible(true);
  }

  /**
   * 判断模板是否存在
   *
   * @throws Exception
   */
  public static boolean isExistTemplate(String tplName) throws Exception {
    try {
      Template mytpl = _tplConfig.getTemplate(tplName, "UTF-8");
      if (mytpl == null) {
        return false;
      }
    } catch (Exception e) {
      // update-begin--Author:scott  Date:20180320 for：解决问题 - 错误提示sql文件不存在，实际问题是sql
      // freemarker用法错误-----
      if (e instanceof ParseException) {
        log.error(e.getMessage(), e.fillInStackTrace());
        throw new Exception(e);
      }
      log.debug("----isExistTemplate----" + e.toString());
      // update-end--Author:scott  Date:20180320 for：解决问题 - 错误提示sql文件不存在，实际问题是sql
      // freemarker用法错误------
      return false;
    }
    return true;
  }

  /**
   * 解析ftl模板
   *
   * @param tplName 模板名
   * @param paras 参数
   * @return
   */
  public static String parseTemplate(String tplName, Map<String, Object> paras) {
    try {
      log.debug(" minidao sql templdate : " + tplName);
      StringWriter swriter = new StringWriter();
      Template mytpl = _tplConfig.getTemplate(tplName, ENCODE);
      if (paras.containsKey(MINI_DAO_FORMAT)) {
        throw new RuntimeException("DaoFormat 是 minidao 保留关键字，不允许使用 ，请更改参数定义！");
      }
      paras.put(MINI_DAO_FORMAT, new SimpleFormat());
      mytpl.process(paras, swriter);
      String sql = getSqlText(swriter.toString());
      paras.remove(MINI_DAO_FORMAT);
      return sql;
    } catch (Exception e) {
      log.error(e.getMessage(), e.fillInStackTrace());
      log.error("发送一次的模板key:{ " + tplName + " }");
      // System.err.println(e.getMessage());
      // System.err.println("模板名:{ "+ tplName +" }");
      throw new RuntimeException("解析SQL模板异常");
    }
  }

  /**
   * 解析ftl
   *
   * @param tplContent 模板内容
   * @param paras 参数
   * @return String 模板解析后内容
   */
  public static String parseTemplateContent(String tplContent, Map<String, Object> paras) {
    try {
      StringWriter swriter = new StringWriter();
      if (stringTemplateLoader.findTemplateSource("sql_" + tplContent.hashCode()) == null) {
        stringTemplateLoader.putTemplate("sql_" + tplContent.hashCode(), tplContent);
      }
      Template mytpl = _sqlConfig.getTemplate("sql_" + tplContent.hashCode(), ENCODE);
      if (paras.containsKey(MINI_DAO_FORMAT)) {
        throw new RuntimeException("DaoFormat 是 minidao 保留关键字，不允许使用 ，请更改参数定义！");
      }
      paras.put(MINI_DAO_FORMAT, new SimpleFormat());
      mytpl.process(paras, swriter);
      String sql = getSqlText(swriter.toString());
      paras.remove(MINI_DAO_FORMAT);
      return sql;
    } catch (Exception e) {
      log.error(e.getMessage(), e.fillInStackTrace());
      log.error("发送一次的模板key:{ " + tplContent + " }");
      // System.err.println(e.getMessage());
      // System.err.println("模板内容:{ "+ tplContent +" }");
      throw new RuntimeException("解析SQL模板异常");
    }
  }

  /** 除去无效字段，去掉注释 不然批量处理可能报错 去除无效的等于 */
  private static String getSqlText(String sql) {
    // 将注释替换成""
    sql = p.matcher(sql).replaceAll("");
    sql = sql.replaceAll("\\n", " ").replaceAll("\\t", " ").replaceAll("\\s{1,}", " ").trim();
    // 去掉 最后是 where这样的问题
    if (sql.endsWith("where") || sql.endsWith("where ")) {
      sql = sql.substring(0, sql.lastIndexOf("where"));
    }
    // 去掉where and 这样的问题
    int index = 0;
    while ((index = StringUtils.indexOfIgnoreCase(sql, "where and", index)) != -1) {
      sql = sql.substring(0, index + 5) + sql.substring(index + 9, sql.length());
    }
    // 去掉 , where 这样的问题
    index = 0;
    while ((index = StringUtils.indexOfIgnoreCase(sql, ", where", index)) != -1) {
      sql = sql.substring(0, index) + sql.substring(index + 1, sql.length());
    }
    // 去掉 最后是 ,这样的问题
    if (sql.endsWith(",") || sql.endsWith(", ")) {
      sql = sql.substring(0, sql.lastIndexOf(","));
    }
    return sql;
  }
}
